package com.pig.openg1.render;

import android.app.ActivityManager;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.opengl.Matrix;
import android.os.SystemClock;
import android.util.Log;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

/***
 * 实现基本的图形渲染
 */
public class GraphOneRender implements GLSurfaceView.Renderer {

    private final String TAG = GraphOneRender.class.getSimpleName();

    private float[] mModelMatrix = new float[16]; // 模型矩阵，存储对象比那换的空间位置
    private float[] mViewMatrix = new float[16]; //视图矩阵，存储视觉空间中的位置
    private float[] mProjMatrix = new float[16]; // 投影矩阵，将场景投影2视口
    private float[] mMVPMatrix = new float[16]; // 总变化矩阵，向着色器传递数据

    //在单精度缓存中，存贮我们的模板中数据
    private FloatBuffer mTriangle1Vertices;
    private FloatBuffer mTriangle2Vertices;
    private FloatBuffer mTriangle3Vertices;

    /** 传递变化矩阵 */
    private int mMVpMatrixHandle;

    /** this will be used to pass in model position information */
    private int mPositionHandle;

    /** this will be used to pass in model color information */
    private int mColorHandle;

    /**  how many bytes per float */
    private int mBytePerFloat = 4;

    /** how many elements per vertex. */
    private int mStrideBytes = 7 * mBytePerFloat;

    /** offset of the position data */
    private int mPositionOffset = 0;

    /** size of the position data in elements */
    private int mPostionDataSize = 3;

    /** offset of the color data */
    private int mColorOffset = 3;

    /**  size of the color data in elements */
    private int mColorDataSize = 4;

    public GraphOneRender()
    {
        //define point for equilateral triangles.
        float [] mTriangleVertexPoint = {
                -0.5f, -0.25f, 0.0f,
                1.0f, 0.0f, 0.0f, 1.0f,

                0.5f, -0.25f, 0.0f,
                0.0f, 0.0f, 1.0f, 1.0f,

                0.0f, 0.559016994f, 0.0f,
                0.0f, 1.0f, 0.0f, 1.0f};

        float[] mTriangle2VertexPoint = {
                -0.5f, -0.25f, 0.0f,
                1.0f, 1.0f, 0.0f, 1.0f,

                0.5f, -0.25f, 0.0f,
                0.0f, 1.0f, 1.0f, 1.0f,

                0.0f, 0.559016994f, 0.0f,
                1.0f, 0.0f, 1.0f, 1.0f};

        float[] mTriangle3VertexPoint = {
                -0.5f, -0.25f, 0.0f,
                1.0f, 1.0f, 1.0f, 1.0f,

                0.5f, -0.25f, 0.0f,
                0.5f, 0.5f, 0.5f, 1.0f,

                0.0f, 0.559016994f, 0.0f,
                0.0f, 0.0f, 0.0f, 1.0f};


        mTriangle1Vertices = ByteBuffer.allocateDirect(mTriangleVertexPoint.length * mBytePerFloat)
                .order(ByteOrder.nativeOrder()).asFloatBuffer();
        mTriangle2Vertices = ByteBuffer.allocateDirect(mTriangle2VertexPoint.length * mBytePerFloat)
                .order(ByteOrder.nativeOrder()).asFloatBuffer();
        mTriangle3Vertices = ByteBuffer.allocateDirect(mTriangle3VertexPoint.length * mBytePerFloat)
                .order(ByteOrder.nativeOrder()).asFloatBuffer();

        mTriangle1Vertices.put(mTriangleVertexPoint).position(0);
        mTriangle2Vertices.put(mTriangle2VertexPoint).position(0);
        mTriangle3Vertices.put(mTriangle3VertexPoint).position(0);



    }

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {

        // set the background clear color to gray
        GLES20.glClearColor(0.8f,0.8f,0.8f,0.4f);
        // position the eye behind the origin
        float eyeX = 0.0f;
        float eyeY = 0.0f;
        float eyeZ = 1.5f;
        //we are looking toward the distance
        float lookX = 0.0f;
        float lookY = 0.0f;
        float lookZ = -5.0f;
        // set out up vector this us where out head would be pointing were we holding he camera
        float upX = 0.0f;
        float upY = 1.0f;
        float upZ  = 0.0f;

        Matrix.setLookAtM(mViewMatrix,0,eyeX,eyeY,eyeZ,
                lookX,lookY,lookZ,
                upX,upY,upZ);
        String mVertexShader =
                "uniform mat4 uMVPMatrix;      \n"		// A constant representing the combined model/view/projection matrix.

                        + "attribute vec4 aPosition;     \n"		// Per-vertex position information we will pass in.
                        + "attribute vec4 aColor;        \n"		// Per-vertex color information we will pass in.

                        + "varying vec4 vColor;          \n"		// This will be passed into the fragment shader.

                        + "void main()                    \n"		// The entry point for our vertex shader.
                        + "{                              \n"
                        + "   vColor = aColor;          \n"		// Pass the color through to the fragment shader.
                        // It will be interpolated across the triangle.
                        + "   gl_Position = uMVPMatrix   \n" 	// gl_Position is a special variable used to store the final position.
                        + "               * aPosition;   \n"     // Multiply the vertex by the matrix to get the final point in
                        + "}                              \n";    // normalized screen coordinates.
        String mFragmentShader =
                "precision mediump float;       \n"		// Set the default precision to medium. We don't need as high of a
                        // precision in the fragment shader.
                        + "varying vec4 vColor;          \n"		// This is the color from the vertex shader interpolated across the
                        // triangle per fragment.
                        + "void main()                    \n"		// The entry point for our fragment shader.
                        + "{                              \n"
                        + "   gl_FragColor = vColor;     \n"		// Pass the color directly through the pipeline.
                        + "}                              \n";

        int mVertexShaderHandle = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER);
        if(mVertexShaderHandle != 0 )
        {
            GLES20.glShaderSource(mVertexShaderHandle,mVertexShader);
            GLES20.glCompileShader(mVertexShaderHandle);
            int[] complied = new int[1];
            GLES20.glGetShaderiv(mVertexShaderHandle,GLES20.GL_COMPILE_STATUS,complied,0);
            if(complied[0]== 0 )
            {
                Log.e(TAG,GLES20.glGetShaderInfoLog(mVertexShaderHandle) + "\t 顶点片元加载失败！");
                GLES20.glDeleteShader(mVertexShaderHandle);
                mVertexShaderHandle = 0;
            }
        }
        if(mVertexShaderHandle == 0 )
        {
            throw new RuntimeException("Error create vertex shader");
        }
        int mFragmentShaderHandle = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER);
        if(mFragmentShaderHandle != 0 )
        {
            GLES20.glShaderSource(mFragmentShaderHandle,mFragmentShader);
            GLES20.glCompileShader(mFragmentShaderHandle);
            int[] complied = new int[1];
            GLES20.glGetShaderiv(mFragmentShaderHandle,GLES20.GL_COMPILE_STATUS,complied,0);
            if(complied[0] == 0 )
            {
                Log.e(TAG,GLES20.glGetShaderInfoLog(mFragmentShaderHandle) + "\t 帧片元加载失败！");
                GLES20.glDeleteShader(mFragmentShaderHandle);
                mFragmentShaderHandle = 0;
            }
        }
        if(mFragmentShaderHandle == 0 )
        {
            throw new RuntimeException("Error create fragment shader");
        }

        int mProgramHandle = GLES20.glCreateProgram();
        if(mProgramHandle != 0 )
        {
            //bind the vertex /frag to the program
            GLES20.glAttachShader(mProgramHandle,mVertexShaderHandle);
            GLES20.glAttachShader(mProgramHandle,mFragmentShaderHandle);

            // bind attribute
            GLES20.glBindAttribLocation(mProgramHandle,0,"aPosition");
            GLES20.glBindAttribLocation(mProgramHandle,1,"aColor");
            //  link the two shader together into a program
            GLES20.glLinkProgram(mProgramHandle);
            int[] linkStatus = new int[1];
            GLES20.glGetProgramiv(mProgramHandle,GLES20.GL_LINK_STATUS,linkStatus,0);
            if(linkStatus[0] == 0 )
            {
                Log.e(TAG,GLES20.glGetProgramInfoLog(mProgramHandle) + "-> 加载 program 失败！");
                GLES20.glDeleteProgram(mProgramHandle);
                mProgramHandle = 0;
            }

        }
        if(mProgramHandle == 0 )
        {
            throw new RuntimeException("Error creating program");
        }

        mMVpMatrixHandle = GLES20.glGetUniformLocation(mProgramHandle,"uMVPMatrix");
        mPositionHandle = GLES20.glGetAttribLocation(mProgramHandle,"aPosition");
        mColorHandle = GLES20.glGetAttribLocation(mProgramHandle,"aColor");
        GLES20.glUseProgram(mProgramHandle);
    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {

        GLES20.glViewport(0,0,width,height);
        float ratio = (float)width/height;
        Matrix.frustumM(mProjMatrix,0,-ratio,ratio,-1.0f,1.0f,1.0f,10.0f);
//        Matrix.setLookAtM(mViewMatrix,0,
//                0.0f,0.0f,2.0f,
//                0.0f,0.0f,0.0f,
//                3.0f,0.0f,0.0f);
    }

    @Override
    public void onDrawFrame(GL10 gl) {

        GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT| GLES20.GL_COLOR_BUFFER_BIT);
        long time = SystemClock.uptimeMillis() %10000L;
        float angleDegree = (360.0f/10000.0f) * time;

        //draw the triangle facing straight on.
        Matrix.setIdentityM(mModelMatrix,0);
        Matrix.rotateM(mModelMatrix,0,angleDegree,0.0f,0.0f,1.0f);
        drawTriangle(mTriangle1Vertices);


        Matrix.setIdentityM(mModelMatrix,0);
        Matrix.translateM(mModelMatrix,0,0.0f,1.0f,0.0f);
        //以X 轴未坐标旋转90度
        Matrix.rotateM(mModelMatrix,0,90.0f,1.0f,0.0f,0.0f);
        Matrix.rotateM(mModelMatrix,0,angleDegree,0.0f,0.0f,1.0f);
        drawTriangle(mTriangle2Vertices);

        Matrix.setIdentityM(mModelMatrix,0);
        Matrix.translateM(mModelMatrix,0,1.0f,0.0f,0.0f);
        Matrix.rotateM(mModelMatrix,0,90.0f,0.0f,1.0f,0.0f);
        Matrix.rotateM(mModelMatrix,0,angleDegree,0.0f,0.0f,1.0f);
        drawTriangle(mTriangle3Vertices);

    }


    private void drawTriangle(FloatBuffer buffer)
    {
        //pass in the position information
        buffer.position(mPositionOffset);
        GLES20.glVertexAttribPointer(mPositionHandle,mPostionDataSize,GLES20.GL_FLOAT,false
                ,mStrideBytes,buffer);
        GLES20.glEnableVertexAttribArray(mPositionHandle);

        //pass in the color information
        buffer.position(mColorOffset);
        GLES20.glVertexAttribPointer(mColorHandle,mColorDataSize,GLES20.GL_FLOAT,false,
                mStrideBytes,buffer);
        GLES20.glEnableVertexAttribArray(mColorHandle);

        Matrix.multiplyMM(mMVPMatrix,0,mViewMatrix,0,mModelMatrix,0);
        Matrix.multiplyMM(mMVPMatrix,0,mProjMatrix,0,mMVPMatrix,0);

        GLES20.glUniformMatrix4fv(mMVpMatrixHandle,1,false,mMVPMatrix,0);
        GLES20.glDrawArrays(GLES20.GL_TRIANGLES,0,3);


    }
}
